﻿using System;
using System.Web.Security;
using System.Collections.Generic;
using System.Data;

namespace System.Web.Security
{

    public enum gfcProviders
    {
        Unknown = 0, Google = 1, FaceBook = 2, Yandex = 3, VKontakte = 4
    }

    public class gfcUser
    {
        #region Members
        gfcProviders gfcprovider;
        public gfcProviders gfcProvider
        {
            get{ return gfcprovider; }
            set { gfcprovider = value; }
        }      
        string id;
        public string Id
        {
            get { return id; }
            set { id = value; }
        }
        private string gfcid;
        public string gfcId
        {
            get
            {
                return gfcid;
            }
            set
            {
                gfcid = value;
                switch(gfcprovider)
                {
                    case gfcProviders.Google:
                        id = string.Format(
                            "{0:D5}{1}"
                            , (int)gfcProviders.Google
                            , gfcid);
                        break;
                    default:
                        id = string.Format(
                            "{0:D5}{1}"
                            , (int)gfcProviders.Unknown
                            , gfcid);
                        break;
                }
            }
        }
        public UInt64 gfcidNum
        {
            get { return Convert.ToUInt64(gfcid); }
        }
        private Guid? guid = null;
        public Guid? Guid
        {
            get { return guid; }
            set { guid = value; }
        }
        public Guid? RootAccountId = null;
        public List<Guid> ChildAccountsId = new List<Guid>();
        string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        string image;
        public string Image
        {
            get { return image; }
            set { image = value; }
        }
        #endregion

        #region Constructors
        public gfcUser()
        {
            this.id = "";
            this.name = "";
            this.image = "";
            this.gfcprovider = gfcProviders.Unknown;
            this.gfcid = "";
        }
        public gfcUser(gfcProviders parProvider, string parGfcidId)
        {
            this.id = "";
            this.name = "";
            this.image = "";
            this.gfcprovider = parProvider;
            this.gfcId = parGfcidId;
        }
        public gfcUser(gfcUser src)
        {
            this.id = src.Id;
            this.name = src.Name;
            this.image = src.image;
            this.gfcprovider = src.gfcProvider;
            this.gfcid = src.gfcId;
            this.Guid = src.Guid;
            this.RootAccountId = src.RootAccountId;
            foreach (System.Guid g in src.ChildAccountsId)
                this.ChildAccountsId.Add(g);
        }
        #endregion

        #region Common methods
        public Exception GetMembershipUser(out MembershipUser u)
        {
            gfcUser uTmp = new gfcUser(this);
            return MembershipEx.GetGfcUser(ref uTmp, out u);
        }
        public static Exception GetMembershipUser(ref gfcUser gfcuser, out MembershipUser u)
        {
            return MembershipEx.GetGfcUser(ref gfcuser, out u);
        }
        public Exception MakeUnionAccountsStructure()
        {
            Exception err = null;
            DataTable tbl1 = new DataTable();
            err = DBGfcUsers.GetById(ref tbl1, this);
            if (err != null || tbl1.Rows.Count <= 0)
                return err;
            DataRow r1 = tbl1.Rows[0];
            if (r1["RootId"] != DBNull.Value)
            {
                this.Guid = (Guid?)r1["Id"];
                this.gfcProvider = (gfcProviders)r1["ProviderId"];
                // Get root node
                this.RootAccountId = (Guid)r1["RootId"];
                this.ChildAccountsId.Clear();
            }
            else
            {
                this.Guid = (Guid?)r1["Id"];
                this.gfcProvider = (gfcProviders)r1["ProviderId"];
                // Get child nodes
                DataTable tbl2 = new DataTable();
                err = DBGfcUsers.GetChildsByRootId(ref tbl2, this.Guid);
                if (err != null)
                    return err;
                this.RootAccountId = null;
                this.ChildAccountsId.Clear();
                foreach (DataRow r2 in tbl2.Rows)
                    this.ChildAccountsId.Add((Guid)r2["Id"]);
            }
            return err;
        }
        #endregion
    }

    public static class MembershipEx
    {
        public static Exception CreateGfcUser(gfcUser gfcRootUser, ref gfcUser gfcNewUser, out MembershipUser u)
        {
            Exception err = null;
            u = null;
            bool bExist = false;
            MembershipCreateStatus mscs;
            err = DBGfcUsers.Exist(gfcNewUser, ref bExist);
            if (err != null)
                return err;
            if (bExist)
                return GetGfcUser(ref gfcNewUser, out u);
            gfcRootUser.MakeUnionAccountsStructure();
            err = DBGfcUsers.Insert(gfcNewUser.gfcProvider, gfcNewUser.Id, gfcRootUser.Guid);
            if (err != null)
                return err;
            try
            {
                u = Membership.CreateUser(gfcNewUser.Id
                            , "ZxCv_2008"
                            , ""
                            , "ZxCv"
                            , "ZxCv_2008"
                            , true
                            , out mscs);
                u.ResetPassword("ZxCv_2008");
            }
            catch (Exception ex)
            {
                DBGfcUsers.Delete(gfcNewUser.Id);
                err = ex;
            }
            return err;
        }
        public static Exception CreateGfcUser(ref gfcUser gfcuser, out MembershipUser u)
        {
            Exception err = null;
            u = null;
            bool bExist = false;
            MembershipCreateStatus mscs;
            err = DBGfcUsers.Exist(gfcuser, ref bExist);
            if (err != null)
                return err;
            if (bExist)
                return GetGfcUser(ref gfcuser, out u);
            err = DBGfcUsers.Insert(gfcuser.gfcProvider, gfcuser.Id, null);
            if (err != null)
                return err;
            try
            {
                u = Membership.CreateUser(gfcuser.Id
                            , "ZxCv_2008"
                            , ""
                            , "ZxCv"
                            , "ZxCv_2008"
                            , true
                            , out mscs);
                u.ResetPassword("ZxCv_2008");
            }
            catch (Exception ex)
            {
                DBGfcUsers.Delete(gfcuser.Id);
                err = ex;
            }
            return err;
        }
        public static Exception GetGfcUser(ref gfcUser gfcuser, out MembershipUser u)
        {
            Exception err = null;
            u = null;
            DBGfcUsers.MakeUnionAccountsStructure(ref gfcuser);
            if (gfcuser.RootAccountId == null)
                u = Membership.GetUser(gfcuser.Id);
            else
                err = GetGfcUser((Guid)gfcuser.RootAccountId, out u);
            return err;
        }
        public static Exception GetGfcUser(Guid guid, out MembershipUser u)
        {
            Exception err = null;
            DataTable tbl = new DataTable();
            u = null;
            err = DBGfcUsers.GetById(ref tbl, guid);
            if (err != null)
                return err;
            if (tbl.Rows.Count <= 0)
                return new Exception("MembershipEx::GetGfcUser(guid)- RootAccountId not found");
            DataRow r = tbl.Rows[0];
            gfcUser tmpU = new gfcUser();
            tmpU.gfcProvider = (gfcProviders)r["ProviderId"];
            tmpU.gfcId = ((string)r["IdStr"]).Substring(5);
            u = Membership.GetUser(tmpU.Id);
            return err;
        }
    }

    public static class MembershipUserEx
    {
        public static string GetGfcUserName(this MembershipUser u)
        {
            return u.UserName;
        }
        public static string GetGfcProvider(this MembershipUser u)
        {
            return u.UserName;
        }
    }
}
